4W - 이스티오 메트릭 커스텀, 프로메테우스와 그라파나
개요
이번에는 메트릭을 커스텀하는 방법을 알아본 후에, 메트릭을 시각화하는 방법까지 파헤쳐본다.
여기에서 말하는 메트릭은 주로 서비스 레벨의 메트릭이다.
이 메트릭을 커스텀하기 위해서는 일단 프로메테우스 메트릭에 익숙할 필요가 있다.
사전 지식
이스티오 서비스 레벨 메트릭
이전 문서에서 짧게 다룬 내용에 대해 조금 더 다룬다.
istio_requests_total{
connection_security_policy="mutual_tls",
# 이 메트릭은 details라는 서비스로 향하는 트래픽에 대한 정보를 담는다.
destination_app="details",
destination_canonical_service="details",
destination_canonical_revision="v1",
destination_principal="cluster.local/ns/default/sa/default",
destination_service="details.default.svc.cluster.local",
destination_service_name="details",
destination_service_namespace="default",
destination_version="v1",
destination_workload="details-v1",
destination_workload_namespace="default",
# 목적지(details) 기준에서 측정한 메트릭이다..
reporter="destination",
request_protocol="http",
response_code="200",
response_flags="-",
# 이 메트릭은 productpage라는 서비스로부터 출발한 트래픽에 대한 정보를 담는다.
source_app="productpage",
source_canonical_service="productpage",
source_canonical_revision="v1",
source_principal="cluster.local/ns/default/sa/default",
source_version="v1",
source_workload="productpage-v1",
source_workload_namespace="default"
} 214
각 엔보이의 메트릭을 종합하여, 서비스 메시의 서비스들끼리 이뤄지는 통신에 대한 메트릭도 제공한다.
이 메트릭은 이스티오를 기본 세팅하고 모니터링했을 때 가장 먼저 마주하게 되는 메트릭으로, 현재 서비스 메시에서 일어나고 있는 트래픽 전반에 대한 정보를 알 수 있게 해준다.
위 예시의 reporter
라벨을 보면 알 수 있듯이, 서비스 간 통신에 두 엔보이가 관여하다보니 하나의 트래픽에 대해서도 2개의 메트릭이 발생하게 된다.
(이것 때문에 재시도 기능을 통해 줄어든 에러율 메트릭을 확인하려면 조금 신경써야 할 부분이 생긴다.)
서비스 레벨 메트릭으로부터 얻을 수 있는 정보는 다음과 같다.
- 지연 시간(latency)
- 트래픽(traffic)
- 에러
- 포화 정도(saturation)
이스티오에서는 별 설정을 하지 않아도 표준으로 세팅된 채 제공되는 메트릭이 몇 가지 있다.[1]
- HTTP, HTTP/2, gRPC
- istio_requests_total - 프록시를 통해 처리된 모든 요청 카운터
- istio_request_duration_milliseconds - 요청 수행시간을 나타내는 버킷(DISTRIBUTION이라고도 한다.)
- istio_request_bytes - HTTP 요청 바디 크기에 대한 버킷
- istio_response_bytes - HTTP 응답 바디 크기에 대한 버킷
- istio_request_messages_total - 클라이언트로부터 온 gRPC 메시지 카운터
- istio_response_messages_total - 서버가 보낸 온 gRPC 메시지 카운터
- TCP
- istio_tcp_sent_bytes_total - TCP 연결 시 보낸(response) 바이트 카운터
- istio_tcp_received_bytes_total - TCP 연결 시 받은(request) 바이트 카운터
- istio_tcp_connections_opened_total - TCP 연결 수를 나타내는 카운터
- istio_tcp_connections_closed_total - TCP 연결 종료 수를 나타내는 카운터
이것들이 기본 메트릭이고, 이들이 가지는 기본 라벨이 또 있다.
몇 가지만 정리하자면,
- Reporter - 이 메트릭을 보고하는 주체로, Source와 Destination으로 나뉜다.
- Source 관련
- Workload - 요청을 처리하는 워크로드 정보
- Principal - peer authentication에서 사용되는 정책
- App, Version - app, version 라벨이 세팅됐을 시 나오는 값
- Canonical - 워크로드에 명시적으로 설정된 서비스와 리비전
- Cluster - 멀티 클러스터에서 요청의 클러스터
- Destination 관련 - Source와 동일하며, 몇 가지가 더 있다.
- Service - 요청을 처리하는 호스트 정보로, 보통 서비스의 FQDN이 들어간다.
- Response Flag - 엔보이에서 노출하는 응답 처리의 세부 정보[2]
- gRPC Response Status - gRPC 통신에서만 보이는 응답 상태에 대한 라벨
metadata:
annotations:
service.istio.io/canonical-name: my-app
service.istio.io/canonical-revision: v2
참고로 canonical은 이렇게 사용자가 워크로드에 명확하게 설정한 값을 기반으로 보여주는데, 설정하지 않았다면 보통 그냥 workload에 나오는 정보와 같다.
Telemetry API
Istio Telemetry는 1.22 버전 이후 메이저로 승격된 관측 가능성 관련 리소스이다.[3]
원래 이스티오에서는 이스티오 전역 설정이나, 워크로드에 어노테이션을 다는 방식으로 관측 가능성 세팅을 지원했다.
이런 방식을 사용성이 너무 제한됐기 때문에 아예 새로운 리소스를 만들어버린 것.
로깅, 메트릭, 트레이싱 등의 설정을 지원한다.
라벨 셀렉팅을 하면 워크로드 단위, 하지 않으면 네임스페이스 단위, 이스티오 루트 네임스페이스에 만들면 전역 설정이 된다.
설정법에 따라서 여러 텔레메트리가 겹치게 되는 경우가 있을 텐데, 이럴 때는 겹치는 설정 부분에 대해서 가장 작은 단위의 설정값이 덮어쓰기한다.
apiVersion: telemetry.istio.io/v1
kind: Telemetry
metadata:
name: foo-tracing-alternate
namespace: baz
spec:
selector:
matchLabels:
service.istio.io/canonical-name: foo
tracing:
- providers:
- name: "zipkin-alternate"
randomSamplingPercentage: 10.00
metrics:
- providers:
- name: prometheus
overrides:
- match:
metric: ALL_METRICS
mode: SERVER
disabled: true
accessLogging:
- providers:
- name: envoy
라벨 셀렉터로 고르고, 트레이싱이나 메트릭, 로깅 설정을 하면 된다.
라벨을 쓰지 않고 targetRefs
로 명시적으로 리소스들을 지정하는 것도 가능하다(waypoint 프록시라면 무조건 이걸 써야 한다).
metrics
metrics:
- providers:
- name: prometheus
reportingInterval: 5s
overrides:
# 서버 쪽 메트릭 비활성화
- match:
metric: ALL_METRICS
mode: SERVER
disabled: true
# request_method, request_host 추가(혹은 변경)
- tagOverrides:
request_method:
value: "request.method"
request_host:
value: "request.host" # CEL 표현식으로 써야 한다.
# REQUEST_COUNT 메트릭 제거
- match:
metric: REQUEST_COUNT
tagOverrides:
response_code:
operation: REMOVE # REMOVE, UPSERT 가능
overides
필드를 통해 덮어쓰기할 메트릭을 정한다.
메트릭 쪽은 match
를 쓸 때 어떤 메트릭을 할 것인지도 세부적으로 지정할 수 있다.
어떤 메트릭 값을 넣을 수 있는지는 서비스 레벨 메트릭 참고.[4]
그래서 그 값에 대해 tagOverrides
필드를 통해 라벨 커스텀을 할 수 있게 되는 것이다.
value
부분은 CEL 표현식으로 작성해야 하는데, 엔보이에서 노출하는 모든 변수를 사용할 수 있다.[5]
이때 서비스 레벨 메트릭 관련해서 노출하고 싶은 정보가 있다면 엔보이 변수 중 filter_state
를 이용해주면 된다.
예를 들어 app 라벨을 이용한 메트릭을 커스텀한다면 filter_state.downstream_peer.app
, filter_stat.upstream_peer.app
를 설정하는 식이다.[6]
EnvoyFilter
엔보이 필터는 말 그대로 엔보이 설정을 직접적으로 만드는 리소스이다.
기본적으로 이스티오에서 제공하는 엔보이 관련 설정 이외에, 지원되지 않고 있는 기능이나 직접적으로 커스텀한 필터를 넣고 싶을 때 직접적으로 엔보이 관련 설정 리소스를 만들고 이것이 엔보이에 적용되도록 할 수 있다.
자유도는 높겠지만 잘못 설정했다가 서비스 메시 전체가 망가질 수도 있기 때문에 조심하게 사용할 필요가 있다.
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: custom-protocol
namespace: istio-config # 이스티오 세팅 시 설정된 meshConfig에 있다.
spec:
# 적용할 엔보이 라벨 셀렉팅
workloadSelector:
labels:
app: mysvc
# 적용할 리소스 유형과 이름
# Waypoint 프록시는 무조건 이걸로 타겟팅해야 한다고 한다.
targetRefs:
- name: waypoint
kind: Gateway
group: gateway.networking.k8s.io
configPatches:
- applyTo: NETWORK_FILTER
match:
context: SIDECAR_OUTBOUND # will match outbound listeners in all sidecars
listener:
portNumber: 9307
filterChain:
filter:
name: "envoy.filters.network.tcp_proxy"
patch:
operation: INSERT_BEFORE
value:
# This is the full filter config including the name and typed_config section.
name: "envoy.extensions.filters.network.mongo_proxy"
typed_config:
"@type": "type.googleapis.com/envoy.extensions.filters.network.mongo_proxy.v3.MongoProxy"
...
- applyTo: NETWORK_FILTER # http connection manager is a filter in Envoy
match:
# context omitted so that this applies to both sidecars and gateways
listener:
filterChain:
filter:
name: "envoy.filters.network.http_connection_manager"
patch:
operation: MERGE
value:
name: "envoy.filters.network.http_connection_manager"
typed_config:
"@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager"
common_http_protocol_options:
idle_timeout: 30s
기본적인 설정은 전부 configPatches
에서 진행된다.
workloadSelector
와 targetRefs
는 대상이 될 엔보이를 선별하는 필드이고, 여기에 추가적으로 priority
필드로 적용 순서를 명시하는 방법이 있긴 하다.
priority
는 위에서 언급한 모든 순서 앞단에서 명시적으로 설정되는 순위라 보면 되겠다.
아무튼 핵심이 되는 configPatches
를 중점적으로 보면 된다.
서비스 레벨 메트릭 커스텀
추가적인 서비스 레벨의 메트릭이나 라벨을 넣고 싶다면 위에서 본 Istio EnvoyFilter나 Istio Telemetry를 통해 메트릭을 등록하는 작업을 해야 한다.
(참고로 두 리소스를 같이 사용할 수 없는데, 결론만 먼저 말하면 1.21부터는 텔레메트리 리소스를 사용하는 게 기본이다.)
이때 개념을 조금 구분해서 이해할 필요가 있다.
- 메트릭 - 그냥 메트릭.
- 디멘션(dimension) - 이스티오 메트릭으로서 노출할 라벨을 말한다.
- 속성(attribute) - 엔보이 단에서 노출하는 정보를 말하며, 이걸 설정하면 디멘션으로 이스티오 메트릭으로서 노출이 가능하게 된다.
서비스 레벨의 메트릭은 결국 엔보이에서 노출되는 메트릭을 조합해서 보여주는 메트릭이란 것을 명심해야 한다.
이때 엔보이에서 기본적으로 노출하는 속성 정보를 속성(attribute)이라고 부르는 것이다.
이걸 프로메테우스 라벨로 메트릭에 노출시키기 위해서는 추가적인 작업이 필요한데, 이걸 차원(dimension)을 추가한다고 표현한다.
그래서 메트릭 커스텀을 한다고 하면 사실 크게 세 가지 방식으로 조작을 분류할 수 있다.
- 완전히 새로운 메트릭을 추가하는 방식 - Istio WasmPlugin, Istio EnvoyFilter등의 세팅이 필수적이다.
- 이미 존재하던 속성을 기존 메트릭에 라벨(디멘션)로 추가하는 방식 - Istio Telemetry로 설정할 수 있다.
- 기존에 없던 속성을 추가하는 방식 - Istio WasmPlugin 등으로 세팅해야 한다.
- 프메 메트릭으로서 노출되기 위해서는 위의 방식 들을 활용해야 한다.
그래서 엔보이에서 먼저 메트릭이나 라벨을 서비스 레벨에서 잡히도록 만들고, 서비스 레벨에서 라벨 커스텀을 한다고 이해하자.
프로메테우스에서는 그냥 라벨이라 부르는 것들을 굳이 속성이라 부르기도 하고 디멘션이라 부르기도 하는 게 다 이유가 있는 거다..
위 방법들에 대해서 각각 실습을 시도했다.
엔보이에서 기본으로 노출하는 메트릭은 이 문서에 담겨있다.[7]
여기에 추가적으로 이스티오가 자체적으로 추가해주는 라벨 값들이 있다.[3:1]
이들은 통신을 하는 상대에 대한 정보를 나타내기 위한 라벨로, 이들은 엔보이 라벨 중 filter_state
의 하위 라벨로서 제공된다.
그래서 filter_state.upstream_peer
, filter_state.downstream_peer
와 같은 식으로 사용하면 된다.
이밖에도 엔보이가 실행되고 있는 환경, 즉 노드에 대한 정보도 노출하는데 이건 xds.node.metadata
라는 필드에 담긴다.
구체적으로 어떤 값이 담기는지 보고 싶다면 엔보이의 관리자 엔드포인트(기본 localhost:15000/server_info
)에서 값을 까보자.
버전 업데이트에 따른 변경
어차피 실습 부분에서 다시금 다루는 내용이니 간단하게만 보고 넘어가도 좋다.
1.25 버전을 기준으로 현재라고 치고, 과거의 방식과의 차이점을 간단하게 다룬다.
과거(위 문서는 1.17 버전)에는 이스티오 관련 메트릭은 그냥 upstream_peer
이라고 하는 식으로 지원했다.[4:1]
1.21부터는 엔보이필터를 이용해서 메트릭을 커스텀하는 방식을 지원하지 않는다.[^7]
구체적으로는 두 설정이 충돌하기 때문에 그렇다.[^8]
이에 따라 과거에는 이스티오 오퍼레이터로 기본 설치할 때 같이 깔리던 여러 엔보이 필터가 최신 버전에서는 기본으로 깔리지 않는다.
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
values:
telemetry:
enabled: true
v2:
enabled: false
이것과 관련해서 아예 이스티오 오퍼레이터를 이용한 설치 방식에서도 세팅 차이가 발생한다.
1.18 이전 버전에서 Istio Telemetry를 사용하려면 위와 같이 세팅을 해야 한다.
현 버전에서는 telemetry
라는 필드 자체가 없다.
기본으로 노출하는 속성 정보에 대한 것도 살짝 차이가 있다.
그 시절의 이스티오에서는 peer 메타데이터 관련해서 다음의 값들을 추가로 노출해주었다.[6:1]
이 속성들은 upstream_peer.istio_version
이런 식으로 접근하는 것이 가능했다.
그런데 최신 버전에서는 이런 정보를 기본 속성으로 노출해주지 않는다..
또한 이 정보들을 접근하고자 할 때는 filter_state.upstream_peer
이런 식으로 접근해야 한다.
그렇다고 이전의 속성들을 아예 안 보여주는 건 아니고, xds.node.metadata
라는 필드로 노출해준다.
엔보이의 런타임 설정 정보에서 볼 수 있도록 바꿨다고 보면 되겠다.
Prometheus Operator
쿠버네티스 환경에서 프로메테우스를 조금 더 쉽게 관리할 수 있도록 도와주는 오퍼레이터.
프로메테우스에서 활용되는 다양한 설정이나 기능들을 CRD로 만들어서 클러스터적으로 프로메테우스를 관리할 수 있도록 도와준다.
리소스
이 오퍼레이터에는 다양한 CRD가 존재한다.
위에서도 말했듯, 이 CRD들은 대체로 프로메테우스에서 활용되는 기능들을 클러스터 리소스로서도 관리할 수 있도록 만들어진 것들이다.
크게는 두 가지로 구분을 지을 수 있는데, 이번에 볼 것은 모니터 리소스이다.
서비스 모니터
프로메테우스에서 설정해야 하는 요소들 역시 각각 하나의 리소스로서 관리할 수 있다.
가령 어떤 서비스의 대상이 되는 파드들의 메트릭을 추적하고 싶을 때는 서비스 모니터라는 리소스를 만든다.
kind: Service
apiVersion: v1
metadata:
name: example-app
labels:
app: example-app
spec:
selector:
app: example-app
ports:
- name: web
port: 8080
---
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: example-app
labels:
team: frontend
spec:
selector:
matchLabels:
app: example-app
endpoints:
- port: web
ServiceMonitor의 경우 이런 식으로 작성한다.
이게 무엇이냐, 서비스 모니터 리소스는 어떤 서비스를 라벨 기반으로 추적한다.
위의 서비스는 자신의 라벨(라벨 셀렉터 부분 말고, 서비스 메타데이터의 라벨이란 것에 유념)로 app: example-app
을 가지고 있다.
서비스 모니터는 이 라벨을 추적하여 자신이 메트릭을 수집할 대상이 되는 서비스를 찾아낸다.
이후에 이 서비스가 가지는 엔드포인트슬라이스을 추적하여 실제 트래픽을 받는 파드를 알아내고, 그 파드로부터 메트릭을 긁어온다!
프로메테우스의 서비스 디스커버리 설정에 이렇게 찾아진 파드들이 자동으로 등록되어, 프로메테우스를 통해 해당 파드들이 노출하는 메트릭을 자연스럽게 긁어올 수 있게 된다.
그림으로 보기 편하게 예를 들면 이런 식이다.[8]
서비스 모니터 리소스는 서비스 라벨을 보는 방식이니 서비스의 라벨 셀렉터만 설정한다던가 하는 실수에 유의하자.
실습 진행
프로메테우스 세팅
본격적으로 메트릭을 커스텀하기 전에, 조금이라도 편하게 보기 위해서 먼저 프로메테우스를 세팅한다.
구체적으로는 위에서 프로메테우스 오퍼레이터를 설치하는 것이다.
(더 구체적으로는 그라파나까지 같이 세팅된 kube prom stack을 설치하는 것이다.)
책에 나오는 예엣날 버전의 프로메테우스 설치
가급적 최신 버전들을 이용하면서 스터디 시간에 나오는 이전 버전들과 비교를 하는 것도 내 목표 중 하나인 관계로 나는 이전 버전을 세팅하진 않고 정리만 한다.
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
cat << EOF > prom-values-2.yaml
prometheusOperator:
tls:
enabled: false
admissionWebhooks:
patch:
enabled: false
prometheus:
service:
type: NodePort
nodePort: 30001
grafana:
service:
type: NodePort
nodePort: 30002
EOF
kubectl create ns prometheus
helm install prom prometheus-community/kube-prometheus-stack --version 13.13.1 \
-n prometheus -f ch7/prom-values.yaml -f prom-values-2.yaml
일단 프롬 스택을 헬름으로 설치한다.
(참고로 이름이 스택인 이유는 프로메테우스 오퍼레이터와 더불어 그라파나 등 다양한 리소스를 한꺼번에 설치하는 올인원 차트이기 때문이다.)
ch7/prom-values
파일은 무식하게 헬름 values 파일을 갖다 박고 실습에 맞게 수정한 듯한데, 크기가 너무 크고 불편해서 아예 특정 부분들만 덮어씌우는 추가 values 파일을 만들어서 사용한다.
대단한 걸 덮어씌우는 것은 아니고 단순히 사전에 설정한 포트를 사용하고 편의를 위해 tls를 비활성화하는 정도만 세팅한다.
최신 버전 프롬 스택 설치
crds:
enabled: true
defaultRules:
create: false
global:
rbac:
create: true
createAggregateClusterRoles: false
pspEnabled: false
prometheus-windows-exporter:
prometheus:
monitor:
enabled: false
releaseLabel: false
alertmanager:
enabled: false
grafana:
enabled: true
adminUser: admin
adminPassword: prom-operator
sidecar:
dashboards:
enabled: true
datasources:
enabled: true
defaultDatasourceEnabled: true
isDefaultDatasource: true
name: Prometheus
uid: prometheus
## Set method for HTTP to send query to datasource
httpMethod: POST
prometheusServiceName: prometheus-operated
label: grafana_datasource
labelValue: "1"
alertmanager:
enabled: false
kubernetesServiceMonitors:
enabled: true
kubeApiServer:
enabled: false
kubelet:
enabled: false
kubeControllerManager:
enabled: false
coreDns:
enabled: false
kubeEtcd:
enabled: false
kubeScheduler:
enabled: false
kubeProxy:
enabled: false
kubeStateMetrics:
enabled: false
nodeExporter:
enabled: false
prometheusOperator:
enabled: true
tls:
enabled: false
admissionWebhooks:
patch:
enabled: false
prometheus:
service:
nodePort: 30090
type: ClusterIP
이건 내가 최신 프롬 스택의 values 파일을 까서 일일히 세팅한 것이다.
책 실습에 나온 설정 부분들을 최대한 비슷하게 세팅했고, 아울러 스터디 시간에 추가적으로 세팅한 부분들도 적용했다.
다만 눈으로 보면서 세팅을 했다보니 조금 다른 부분이 있을 수도 있으니 이 파일을 이용하려면 참고하자.
k create ns prometheus
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm install prom prometheus-community/kube-prometheus-stack --version 71.1.0 \
-n prometheus -f prom-values-3.yaml
kubectl patch svc -n prometheus prom-kube-prometheus-stack-prometheus -p '{"spec": {"type": "NodePort", "ports": [{"port": 9090, "targetPort": 9090, "nodePort": 30001}]}}'
kubectl patch svc -n prometheus prom-grafana -p '{"spec": {"type": "NodePort", "ports": [{"port": 80, "targetPort": 3000, "nodePort": 30002}]}}'
프롬 스택은 그라파나에 대한 상세한 커스텀을 values에서 지원하지 않기에 그라파나 서비스를 바로 NodePort로 세팅하는 것이 불가능하다.
어차피 바로 노드포트로 세팅할 수 없는 김에 프로메테우스 쪽 서비스도 이후에 세팅하는 식으로 진행했다.
이렇게 세팅이 된다면 성공이다.
30001 포트로 프메, 30002로 그라파나에 접속할 수 있는 것까지 확인하자.(그라파나 id: admin passwd: prom-operator)
모니터 리소스를 통한 이스티오 메트릭 스크래핑 설정
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: istio-component-monitor
namespace: prometheus
labels:
monitoring: istio-components
release: prom
spec:
jobLabel: istio
targetLabels: [app]
selector:
matchExpressions:
- {key: istio, operator: In, values: [pilot]}
namespaceSelector:
any: true
endpoints:
- port: http-monitoring # 15014
interval: 15s
서비스모니터 리소스를 통해 컨트롤 플레인의 메트릭을 먼저 수집해본다.
만약 이 리소스를 사용하고자 하는 네임스페이스에서 생성하고 이를 적용하게 하려면 프로메테우스 리소스에서 모니터 리소스를 수집하는 네임스페이스에 대한 설정을 추가적으로 해줘야 한다.
이렇게 서비스 디스커버리에 잡히게 된다면 성공이다.
apiVersion: monitoring.coreos.com/v1
kind: PodMonitor
metadata:
name: envoy-stats-monitor
namespace: prometheus
labels:
monitoring: istio-proxies
release: prom
spec:
selector:
matchExpressions:
- {key: istio-prometheus-ignore, operator: DoesNotExist}
namespaceSelector:
any: true
jobLabel: envoy-stats
podMetricsEndpoints:
- path: /stats/prometheus
interval: 15s
relabelings:
- action: keep
sourceLabels: [__meta_kubernetes_pod_container_name]
regex: "istio-proxy"
- action: keep
sourceLabels: [__meta_kubernetes_pod_annotationpresent_prometheus_io_scrape]
- sourceLabels: [
__address__, __meta_kubernetes_pod_annotation_prometheus_io_port]
action: replace
regex: \d+)?;(\d+
replacement: $1:$2
targetLabel: __address__
- action: labeldrop
regex: "__meta_kubernetes_pod_label_(.+)"
- sourceLabels: [__meta_kubernetes_namespace]
action: replace
targetLabel: namespace
- sourceLabels: [__meta_kubernetes_pod_name]
action: replace
targetLabel: pod_name
다음은 데이터 플레인의 메트릭을 수집해보자.
위 예시는 어떤 네임스페이스에 있던 메트릭 수집 무시 관련 라벨이 안 붙어 있는 파드들의 메트릭을 긁어온다.
메트릭 엔드포인트에 대한 리라벨링을 진행하는데, 대충 설명하자면,
- 컨테이너 이름 관련 라벨에 istio-proxy가 있는 메트릭만 유지
- 참고로 keep이란 행위는 해당 조건을 만족하지 않으면 대상에서 제외한다.
- 스크랩 관련 어노테이션이 달린 파드들에 대한 메트릭만 유지
- address라는 라벨 커스텀
- 기존 address 라벨에서 ip 주소만 가져오고, 어노테이션에 달린 포트를 붙인다.
__address__
는 스크래핑 주소에 대한 메타 라벨로 실제 메트릭을 긁어오는 경로에 영향을 준다.[9]
- 파드 라벨은 전부 버린다.
- labeldrop이란 행위는 메트릭을 버리는 게 아니라 라벨만 버린다.
- 네임스페이스 라벨을 추가한다.
- 파드 이름 라벨을 추가한다.
이 녀석도 위와 마찬가지로 서비스 디스커버리 탭에 추가가 되면 성공이다.
이제 프록시 레벨, 서비스 레벨의 메트릭도 프로메테우스를 통해 볼 수 있게 됐다.
메트릭 커스텀 - 1.25 버전 기준
1.25 버전 기준으로는 엔보이필터를 이용해 메트릭을 커스텀하는 방식은 deprectated됐고, 대신 telemetry 리소스를 사용해야 한다.
엔보이 필터로 하는 것이 불가능한 것은 아니지만, 엔보이 필터 자체가 이스티오에서 제공되지 않는 기능들을 커스텀할 때 사용하는 최후의 보루이기에 에러를 해결하기도 어려운지라 가능한 telemetry를 사용하는 것이 아주 강력하게 권장된다.
기술 부채 제조기 이스티오
기존 메트릭에 추가 라벨 설정
istio_requests_total{connection_security_policy="mutual_tls", container="istio-proxy", destination_app="webapp", destination_canonical_revision="latest", destination_canonical_service="webapp", destination_cluster="Kubernetes", destination_principal="spiffe://cluster.local/ns/istioinaction/sa/webapp", destination_service="webapp.istioinaction.svc.cluster.local", destination_service_name="webapp", destination_service_namespace="istioinaction", destination_workload="webapp", destination_workload_namespace="istioinaction", instance="10.10.0.7:15020", job="prometheus/envoy-stats-monitor", namespace="istioinaction", pod="webapp-7c96945758-5c69g", pod_name="webapp-7c96945758-5c69g", reporter="destination", request_protocol="http", response_code="200", response_flags="-", source_app="istio-ingressgateway", source_canonical_revision="latest", source_canonical_service="istio-ingressgateway", source_cluster="Kubernetes", source_principal="spiffe://cluster.local/ns/istio-system/sa/istio-ingressgateway-service-account", source_version="unknown", source_workload="istio-ingressgateway", source_workload_namespace="istio-system"}
먼저 기존 istio_request_total 메트릭의 라벨은 이런 상태이다.
여기에는 request_protocol
이 들어가 있다.
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
profile: demo
values:
telemetry:
v2:
prometheus:
configOverride:
inboundSidecar:
metrics:
- name: requests_total
dimensions:
upstream_proxy_version: upstream_peer.istio_version
source_mesh_id: node.metadata['MESH_ID']
tags_to_remove:
- request_protocol
outboundSidecar:
metrics:
- name: requests_total
dimensions:
upstream_proxy_version: upstream_peer.istio_version
source_mesh_id: node.metadata['MESH_ID']
tags_to_remove:
- request_protocol
gateway:
metrics:
- name: requests_total
dimensions:
upstream_proxy_version: upstream_peer.istio_version
source_mesh_id: node.metadata['MESH_ID']
tags_to_remove:
- request_protocol
책에서 안내하는 이전 버전의 방식은 위와 같이 이스티오 오퍼레이터에 telemtry
필드에 설정을 넣는 것이다.
그런데 이 방식은 1.25 버전 현재 아예 불가능하다.
apiVersion: telemetry.istio.io/v1alpha1
kind: Telemetry
metadata:
name: add-dimension-tags
namespace: istioinaction
spec:
metrics:
- providers:
- name: prometheus
overrides:
- match:
metric: REQUEST_COUNT
mode: CLIENT_AND_SERVER
disabled: false
tagOverrides:
upstream_proxy_version:
operation: UPSERT
value: upstream_peer.istio_version
source_mesh_id:
operation: UPSERT
value: node.metadata['MESH_ID']
request_protocol:
operation: REMOVE
당시 알파 단계였던 텔레메트리 리소스 양식을 활용해서 만드는 방법은 이렇다.[10]
미리 말하지만 이것도 현재 버전에서는 먹히지 않는다.
istio_requests_total{connection_security_policy="mutual_tls", container="istio-proxy", destination_app="webapp", destination_canonical_revision="latest", destination_canonical_service="webapp", destination_cluster="Kubernetes", destination_principal="spiffe://cluster.local/ns/istioinaction/sa/webapp", destination_service="webapp.istioinaction.svc.cluster.local", destination_service_name="webapp", destination_service_namespace="istioinaction", destination_workload="webapp", destination_workload_namespace="istioinaction", instance="10.10.0.8:15020", job="prometheus/envoy-stats-monitor", namespace="istioinaction", pod="webapp-7c96945758-8xtdj", pod_name="webapp-7c96945758-8xtdj", reporter="destination", response_code="200", response_flags="-", source_app="istio-ingressgateway", source_canonical_revision="latest", source_canonical_service="istio-ingressgateway", source_cluster="Kubernetes", source_mesh_id="unknown", source_principal="spiffe://cluster.local/ns/istio-system/sa/istio-ingressgateway-service-account", source_version="unknown", source_workload="istio-ingressgateway", source_workload_namespace="istio-system", upstream_proxy_version="unknown"}
이걸 적용해서 만들어지는 값을 보면, 일단 request_protocol
라벨이 없어지고 source_mesh_id
, upstream_proxy_version
라벨이 추가되는 것을 확인할 수 있다.
그러나 막상 보면 두 값이 unknown으로 표시된다.
그 시절의 이스티오에서는 peer 메타데이터 관련해서 다음의 값들을 추가로 노출해주었다.[11]
그런데 최신 버전에서는 조금도 비슷한 정보가 없다..
엔보이쪽에서 노출된다는 속성값들을 찾아봐도 이스티오 버전에 대한 값을 노출할 수 있는 방법은 보이지 않는다.
애초에 엔보이의 설정 버전에 큰 변화(메이저 버전이 3으로 올라감)가 생기면서 이스티오도 빠르게 발맞추다보니 메트릭 관련해서 상당히 이전 버전과 비슷하게 세팅하는 방법들에 대한 자료가 많지 않은 것 같다.
최근 블로그 글을 보면 죄다 gateway api, ambient 모드에만 치중이 돼있어 api에 생긴 중대한 변화에 대한 마이그레이션 포인트들을 인지하기 힘들다.
문서에서는 node metadata도 노출하긴 한다고 하는데, 막상 다른 자료들을 보더라도 구체적으로 어떻게 노출한다고 하는지 알긴 힘들다.
혼자 눈물의 똥꼬쇼를 하다보니 조금씩 단서들이 나오긴 했다.
엔보이에서 자체적으로 노출해주는 값 중에서 node 관련된 것이 있기는 하다.
node 관련해 노출하는 엔보이의 필드들은 다음과 같다.
위의 값들을 토대로 넣을 값을 수정해보자.
예제에서 나온 방식으로 정확하게 적용된다고 보기는 힘들지만, 아무튼 값을 출력할 수 있기는 하다.
그렇다면 책의 내용처럼 프록시 버전과 메시ID를 정확하게 볼 수 있는 방법은 없을까?
keti catalog-5899bbc954-mqpbt -- curl http://localhost:15000/server_info | fx
답을 찾고자 한다면, 언젠가는 찾기 마련이다.
엔보이를 알아두면 유용한 이유가 바로 이런 것이다!
엔보이 어드민 엔드포인트로 요청을 날려보면 엔보이에 대한 각종 정보를 볼 수 있는데, 이때 이스티오와 관련된 메타데이터는 node.metadata
쪽으로 들어가는 것을 확인할 수 있다.
apiVersion: telemetry.istio.io/v1
kind: Telemetry
metadata:
name: add-extra-label
namespace: istio-system
spec:
metrics:
- providers:
- name: prometheus
overrides:
- match:
metric: REQUEST_COUNT
tagOverrides:
request_protocol:
operation: REMOVE
upstream_proxy_version:
operation: UPSERT
value: "string(xds.node.metadata.ISTIO_VERSION)"
source_mesh_id:
operation: UPSERT
value: "xds.node.metadata.MESH_ID"
이를 기반으로 텔레메트리 리소스를 만들어본다.
이렇게 하면 드디어 원하는 값들을 담은 라벨을 볼 수 있게 된다!
참고로 해당 설정은 엔보이 리스너 설정 쪽으로 들어가게 된다(사진은 삽질하면서 중간에 찍은 거라 값이 조금 다르게 쓰여있다).
새로운 메트릭 만들기 - 보류
새로운 메트릭을 만들고자 할 때는 텔레메트리가 아니라 다른 리소스로 설정을 해줘야 한다.[12]
근데 속성을 추가로 만드는 것에 대한 예시는 있는데, 어째 메트릭을 새로 만드는 예시가 없다.
직접 만들어야 하나..?
이스티오에는 관리하지 않은지 오래 됐지만 그래도 기본적으로 활용할 만한 와즘 플러그인들을 모아두긴 했다.[13]
그러나 여기에도 메트릭을 추가하는 것과 관련된 것은 보이지 않는다.
열심히 찾아봤지만, 역시 메트릭을 추가하는 것과 관련된 마땅한 예제, 자료가 존재하지 않았다.
아무래도 정말로 직접 와즘 플러그인을 만드는 방향을 생각해야 할 것으로 보인다.
향후에 텔레메트리 api에서 새로운 메트릭을 추가할 수 있도록 양식이 변경될 가능성이 있을까 모르겠다.
새로운 속성 만들기
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: attribute-gen-example
namespace: istioinaction
spec:
configPatches:
## Sidecar Outbound
- applyTo: HTTP_FILTER
match:
context: SIDECAR_OUTBOUND
listener:
filterChain:
filter:
name: envoy.filters.network.http_connection_manager
subFilter:
name: istio.stats
proxy:
proxyVersion: ^1\.13.*
patch:
operation: INSERT_BEFORE
value:
name: istio.attributegen
typed_config:
'@type': type.googleapis.com/udpa.type.v1.TypedStruct
type_url: type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm
value:
config:
configuration:
'@type': type.googleapis.com/google.protobuf.StringValue
value: |
{
"attributes": [
{
"output_attribute": "istio_operationId", # 속성 이름
"match": [
{
"value": "getitems", # 속성 값
"condition": "request.url_path == '/items' && request.method == 'GET'"
},
{
"value": "createitem",
"condition": "request.url_path == '/items' && request.method == 'POST'"
},
{
"value": "deleteitem",
"condition": "request.url_path == '/items' && request.method == 'DELETE'"
}
]
}
]
}
vm_config:
code:
local:
inline_string: envoy.wasm.attributegen
runtime: envoy.wasm.runtime.null
새로운 속성을 만들고자 할 때는 원래 엔보이필터 리소스를 이용하는 방식이 기본이었다.
그러나 현재 이걸 세팅하면 지속적으로 에러가 발생한다.
istiod 로그를 보면 wasm 플러그인을 만드는데 실패한다고 표시되고 있다.
그렇다면 어떻게 새로운 속성을 추가할 수 있는가?
이스티오에서는 어차피 와즘을 통해 새로운 필터를 주입하는 방식으로 엔보이 필터를 사용하는 기능을 확장하는 케이스가 많은 만큼, 아예 WasmPlugin이란 리소스를 통해 와즘을 넣는 방식을 제공하고 있다.
다행이라 해야 할지, 현재 attributegen이란 형태의 와즘 바이너리가 현재 제공되고 있어서 이건 코드를 만들지 않고 설정하는 게 가능하다.[14]
apiVersion: extensions.istio.io/v1alpha1
kind: WasmPlugin
metadata:
name: istio-attributegen-filter
spec:
url: https://storage.googleapis.com/istio-build/proxy/attributegen-359dcd3a19f109c50e97517fe6b1e2676e870c4d.wasm
imagePullPolicy: Always
phase: AUTHN
pluginConfig:
attributes:
- output_attribute: "istio_operationId"
match:
- value: "getitems", # 속성 값
condition: "request.url_path == '/items' && request.method == 'GET'"
- value: "createitem",
condition: "request.url_path == '/items' && request.method == 'POST'"
- value: "deleteitem",
condition: "request.url_path == '/items' && request.method == 'DELETE'"
해당 리소스를 적용하면 엔보이 listener 쪽 http 필터가 추가된다.
configDiscovery를 통해 구체적인 설정 정보를 받아가도록 세팅돼있는데, 이건 ecds 설정을 봐야 한다.
istioctl pc ecds webapp-76774fdc79-jb7rj -ojson | fx
설정이 이렇게 들어간 것을 확인할 수 있다.
그 다음부터는 삽질하면서 어떻게 해당 메트릭을 노출할 수 있는지 알아봤다.
결론적으로는, 문서에 나온 그대로 filter_state
에 wasm.istio_operationId
를 키로 접근해야 값이 나온다.
apiVersion: telemetry.istio.io/v1
kind: Telemetry
metadata:
name: custom-tags
namespace: istio-system
spec:
metrics:
- overrides:
- match:
metric: REQUEST_COUNT
mode: CLIENT_AND_SERVER
tagOverrides:
request_operation:
value: filter_state['wasm.istio_operationId']
providers:
- name: prometheus
최종적으로는 이런 식으로 만들어주었다.
curl -s http://$SIMPLEWEB:30000/items --resolve "$SIMPLEWEB:30000:127.0.0.1"
새로운 속성을 지정할 때 url 경로가 /items
여야 하도록 설정했기 때문에, 테스트를 할 때도 당연히 해당 경로를 넣어서 요청해야 한다.
성공적으로 해당 라벨에 원한 값이 추가됐다!
주의사항으로, 텔레메트리 리소스들의 설정이 함께 설정이 되지 않기 때문에 기존 리소스를 반드시 삭제하고 해당 리소스를 적용해야 한다.[15]
그라파나 세팅
이제 메트릭을 시각화하는 툴, 그라파나를 간단하게 보면서 실습을 마친다.
이건 깊게 파지는 않을 것이다.
이전에 프로메테우스 스택을 설치하면서 자연스럽게 그라파나도 같이 세팅이 완료됐다.
추가적으로 세팅해줄 만한 건 이스티오를 위한 대시보드들을 그라파나에 넣어주는 것 뿐이다.
cd ch8
kubectl -n prometheus create cm istio-dashboards \
--from-file=pilot-dashboard.json=dashboards/\
pilot-dashboard.json \
--from-file=istio-workload-dashboard.json=dashboards/\
istio-workload-dashboard.json \
--from-file=istio-service-dashboard.json=dashboards/\
istio-service-dashboard.json \
--from-file=istio-performance-dashboard.json=dashboards/\
istio-performance-dashboard.json \
--from-file=istio-mesh-dashboard.json=dashboards/\
istio-mesh-dashboard.json \
--from-file=istio-extension-dashboard.json=dashboards/\
istio-extension-dashboard.json
cd ..
kubectl label -n prometheus cm istio-dashboards grafana_dashboard=1
라벨로 grafana_dashboard
를 넣은 컨피그맵에 대해 그라파나는 자동으로 대시보드 파일로 인식하고 이를 업로드해준다.
책 실습 코드에 이스티오를 위한 대시보드 파일들이 담겨있으므로 이걸 바로 등록해서 보도록한다.
이렇게 표시된다면 완료.
대시보드 확인
먼저 컨트롤 플레인 대시보드를 본다.
버전에 대한 정보를 왜 그래프로 표시했는지는 모르겠다..굳이..?
컨트롤 플레인에서 사용된 리소스 사용량도 확인할 수 있다.
설정 동기화에 대한 정보도 확인할 수 있는데, pilot 에러는 이전에 메트릭 설정을 엔보이 필터로 넣으려다 발생한 에러에 대한 값이다.
서비스 메시 대시보드에는 전체 리소스들에 대한 정보와 트래픽 성공 실패 여부가 간단하게 담겨 있다.
성능 대시보드쪽을 보면 데이터가 제대로 나오지 않는 것을 볼 수 있다.
이건 쿼리문을 보면 이유를 알 수 있는데, 위의 메트릭은 프로메테우스 오퍼레이터를 설치할 때 기본 Recording Rule과 리라벨링으로 설정되는 메트릭이다.
처음 헬름 설치 시 해당 설정을 하지 않도록 했기 때문에 이 메트릭을 볼 수 없는 것이다.
다음으로 서비스 대시보드를 본다.
sum(irate(istio_tcp_received_bytes_total{reporter="destination", destination_service=~"webapp.istioinaction.svc.cluster.local"}[1m]))
tcp 데이터가 나오지 않아서 뭔가 했는데, TCP 메트릭은 http 통신 시 세팅되는 TCP를 제외하고 정말 TCP로서 연결되는 데이터가 있을 때만 출력된다고 한다.
wasm 관련 대시보드도 존재한다.
avg(envoy_wasm_vm_null_active)
그런데 여기는 쿼리 데이터 자체가 잘못된 케이스이다.
새 버전으로 올라오면서 아무래도 메트릭 값에 변화가 생긴 것으로 추정된다.
처음 알았는데, 컨피그맵으로 등록된 대시보드는 수정이 제대로 반영이 안 된다.
그래서 간단하게 대시보드를 파서 쿼리를 다시 짰는데, 아무튼 wasm 관련한 데이터도 제대로 시각화할 수 있다.
마지막으로 워크로드 대시보드에서도 데이터를 확인할 수 있다.
결론
이스티오에서는 광범위한 메트릭을 노출해주고, 이것들을 커스텀할 수 있도록 다양한 방법을 지원한다.
여태 봤을 때는 커스텀을 하기보다는 그냥 있는 메트릭이나 잘 정제하는 게 이스티오를 좋게 활용하는 방향이라는 생각이 든다.
다만 그럼에도 커스텀을 해야 하는 케이스가 있을 수 있을 텐데, 만약 새로운 메트릭을 추가해야 하는 경우라면 이스티오의 확장 리소스인 엔보이 필터, 와즘 플러그인을 세팅해야 하므로 깊은 숙련도와 개발 역량이 요구된다고 볼 수 있겠다.
이전 글, 다음 글
다른 글 보기
이름 | index | noteType | created |
---|---|---|---|
1W - 서비스 메시와 이스티오 | 1 | published | 2025-04-10 |
1W - 간단한 장애 상황 구현 후 대응 실습 | 2 | published | 2025-04-10 |
1W - Gateway API를 활용한 설정 | 3 | published | 2025-04-10 |
1W - 네이티브 사이드카 컨테이너 이용 | 4 | published | 2025-04-10 |
2W - 엔보이 | 5 | published | 2025-04-19 |
2W - 인그레스 게이트웨이 실습 | 6 | published | 2025-04-17 |
3W - 버츄얼 서비스를 활용한 기본 트래픽 관리 | 7 | published | 2025-04-22 |
3W - 트래픽 가중치 - flagger와 argo rollout을 이용한 점진적 배포 | 8 | published | 2025-04-22 |
3W - 트래픽 미러링 패킷 캡쳐 | 9 | published | 2025-04-22 |
3W - 서비스 엔트리와 이그레스 게이트웨이 | 10 | published | 2025-04-22 |
3W - 데스티네이션 룰을 활용한 네트워크 복원력 | 11 | published | 2025-04-26 |
3W - 타임아웃, 재시도를 활용한 네트워크 복원력 | 12 | published | 2025-04-26 |
4W - 이스티오 메트릭 확인 | 13 | published | 2025-05-03 |
4W - 이스티오 메트릭 커스텀, 프로메테우스와 그라파나 | 14 | published | 2025-05-03 |
4W - 오픈텔레메트리 기반 트레이싱 예거 시각화, 키알리 시각화 | 15 | published | 2025-05-03 |
4W - 번외 - 트레이싱용 심플 메시 서버 개발 | 16 | published | 2025-05-03 |
5W - 이스티오 mTLS와 SPIFFE | 17 | published | 2025-05-11 |
5W - 이스티오 JWT 인증 | 18 | published | 2025-05-11 |
5W - 이스티오 인가 정책 설정 | 19 | published | 2025-05-11 |
6W - 이스티오 설정 트러블슈팅 | 20 | published | 2025-05-18 |
6W - 이스티오 컨트롤 플레인 성능 최적화 | 21 | published | 2025-05-18 |
8W - 가상머신 통합하기 | 22 | published | 2025-06-01 |
8W - 엔보이와 iptables 뜯어먹기 | 23 | published | 2025-06-01 |
9W - 앰비언트 모드 구조, 원리 | 24 | published | 2025-06-07 |
9W - 앰비언트 헬름 설치, 각종 리소스 실습 | 25 | published | 2025-06-07 |
7W - 이스티오 메시 스케일링 | 26 | published | 2025-06-09 |
7W - 엔보이 필터를 통한 기능 확장 | 27 | published | 2025-06-09 |
관련 문서
이름 | noteType | created |
---|---|---|
2024-04-07(일) | - | 2024-06-13 |
Prometheus Operator | knowledge | 2025-03-30 |
Prometheus | knowledge | 2025-02-26 |
Prometheus-Adapter | knowledge | 2025-03-04 |
4주차 - 관측 가능성 | project | 2025-02-23 |
4W - 프로메테우스 스택을 통한 EKS 모니터링 | published | 2025-02-28 |
E-이스티오 컨트롤 플레인 성능 최적화 | topic/explain | 2025-05-18 |
E-이스티오 메시 스케일링 | topic/explain | 2025-06-08 |
참고
https://www.envoyproxy.io/docs/envoy/latest/configuration/observability/access_log/usage ↩︎
https://istio.io/latest/docs/reference/config/telemetry/#MetricSelector-IstioMetric ↩︎ ↩︎
https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/advanced/attributes ↩︎
https://istio.io/latest/docs/tasks/observability/metrics/customize-metrics/#use-expressions-for-values ↩︎ ↩︎
https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/advanced/attributes#request-attributes ↩︎
https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/img/custom-metrics-elements.png ↩︎
https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config ↩︎
https://netpple.github.io/docs/istio-in-action/Istio-ch7-observability#741-configuring-existing-metrics ↩︎
https://istio.io/v1.17/docs/tasks/observability/metrics/customize-metrics/ ↩︎
https://istio.io/latest/docs/tasks/observability/metrics/classify-metrics/ ↩︎
https://istio.io/latest/docs/tasks/observability/metrics/classify-metrics/ ↩︎
https://istio.io/latest/docs/tasks/observability/telemetry/ ↩︎